﻿using System.ComponentModel.Composition;
using System.Linq;
using System.ServiceModel.DomainServices.Client.ApplicationServices;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using IssueVision.Data.Web;
using IssueVision.Common;
using MVVMPlugin;

namespace IssueVision.ViewModel
{  
    [ExportPlugin(ViewModelTypes.LoginFormViewModel, PluginType.ViewModel)]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class LoginFormViewModel : ViewModelBase
    {
        #region "Private Data Members"
        private IAuthenticationModel _authenticationModel;
        private IPasswordResetModel _passwordResetModel;
        #endregion "Private Data Members"

        #region "Constructor"
        public LoginFormViewModel()
        {
            _authenticationModel = PluginCatalogService.Container.GetExportedValue<IAuthenticationModel>();
            _passwordResetModel = PluginCatalogService.Container.GetExportedValue<IPasswordResetModel>();

            // set up event handling
            _authenticationModel.LoginComplete += _authenticationModel_LoginComplete;
            _passwordResetModel.GetUserComplete += _passwordResetModel_GetUserComplete;
            _passwordResetModel.SaveUserComplete += _passwordResetModel_SaveUserComplete;

            // Show user login screen first
            IsFlipped = false;

            // Clear any previous error message
            LoginScreenErrorMessage = null;
            ResetPasswordScreenErrorMessage = null;

            // Clear the user name and password
            CurrentUser = new LoginUser();
        }
        #endregion "Constructor"

        #region "Public Properties"

        private bool _isFlipped;

        public bool IsFlipped
        {
            get { return _isFlipped; }
            private set
            {
                if (value != _isFlipped)
                {
                    _isFlipped = value;
                    RaisePropertyChanged("IsFlipped");
                }
            }
        }

        private LoginUser _currentUser;

        public LoginUser CurrentUser
        {
            get { return _currentUser; }
            private set
            {
                if (!ReferenceEquals(_currentUser, value))
                {
                    _currentUser = value;
                    RaisePropertyChanged("CurrentUser");
                }
            }
        }

        private PasswordResetUser _currentPasswordResetUser;

        public PasswordResetUser CurrentPasswordResetUser
        {
            get { return _currentPasswordResetUser; }
            private set
            {
                if (!ReferenceEquals(_currentPasswordResetUser, value))
                {
                    _currentPasswordResetUser = value;
                    RaisePropertyChanged("CurrentPasswordResetUser");
                }
            }
        }

        private string _loginScreenErrorMessage;

        public string LoginScreenErrorMessage
        {
            get { return _loginScreenErrorMessage; }
            private set
            {
                if (!ReferenceEquals(_loginScreenErrorMessage, value))
                {
                    _loginScreenErrorMessage = value;
                    RaisePropertyChanged("LoginScreenErrorMessage");
                }
            }
        }

        private string _resetPasswordScreenErrorMessage;

        public string ResetPasswordScreenErrorMessage
        {
            get { return _resetPasswordScreenErrorMessage; }
            private set
            {
                if (!ReferenceEquals(_resetPasswordScreenErrorMessage, value))
                {
                    _resetPasswordScreenErrorMessage = value;
                    RaisePropertyChanged("ResetPasswordScreenErrorMessage");
                }
            }
        }

        #endregion "Public Properties"

        #region "Public Commands"

        private RelayCommand<LoginUser> _loginCommand;

        public RelayCommand<LoginUser> LoginCommand
        {
            get
            {
                if (_loginCommand == null)
                {
                    _loginCommand = new RelayCommand<LoginUser>(
                        OnLoginCommand,
                        g => g != null);
                }
                return _loginCommand;
            }
        }

        private void OnLoginCommand(LoginUser g)
        {
            if (!_authenticationModel.IsLoggingIn)
            {
                // clear any previous error message
                LoginScreenErrorMessage = null;
                // only call loginAsyc when all input are validated
                if (g.TryValidateProperty("Name") && g.TryValidateProperty("Password"))
                    _authenticationModel.LoginAsync(new LoginParameters(g.Name, g.Password, g.IsPersistent, null));
            }
        }

        private RelayCommand<LoginUser> _resetNowCommand;

        public RelayCommand<LoginUser> ResetNowCommand
        {
            get
            {
                if (_resetNowCommand == null)
                {
                    _resetNowCommand = new RelayCommand<LoginUser>(
                        OnResetNowCommand,
                        g => g != null);     
                }
                return _resetNowCommand;
            }
        }

        private void OnResetNowCommand(LoginUser g)
        {
            if (!_passwordResetModel.IsBusy)
            {
                // clear any previous error message
                LoginScreenErrorMessage = null;
                // only call loginAsyc when user name is valid
                if (g.TryValidateProperty("Name"))
                {
                    _passwordResetModel.GetUserByNameAsync(g.Name);
                }
            }
        }

        private RelayCommand _backToLoginCommand;

        public RelayCommand BackToLoginCommand
        {
            get
            {
                if (_backToLoginCommand == null)
                {
                    _backToLoginCommand = new RelayCommand(
                        OnBackToLoginCommand);
                }
                return _backToLoginCommand;
            }
        }

        private void OnBackToLoginCommand()
        {
            // clear any previous error message
            ResetPasswordScreenErrorMessage = null;
            // clear the password reset screen
            CurrentPasswordResetUser = new PasswordResetUser();
            // reject any changes
            _passwordResetModel.RejectChanges();
            // and flip the screen.
            IsFlipped = false;
        }

        private RelayCommand<PasswordResetUser> _resetPasswordCommand;

        public RelayCommand<PasswordResetUser> ResetPasswordCommand
        {
            get
            {
                if (_resetPasswordCommand == null)
                {
                    _resetPasswordCommand = new RelayCommand<PasswordResetUser>(
                        OnResetPasswordCommand,
                        g => g != null);
                }
                return _resetPasswordCommand;
            }
        }

        private void OnResetPasswordCommand(PasswordResetUser g)
        {
            if (!_passwordResetModel.IsBusy)
            {
                // clear any previous error message
                ResetPasswordScreenErrorMessage = null;
                // only call SaveUserAsync when all input are validated
                if (g.TryValidateProperty("Name") && g.TryValidateProperty("NewPassword")
                    && g.TryValidateProperty("PasswordConfirmation") && g.TryValidateProperty("PasswordAnswer"))
                    _passwordResetModel.SaveUserAsync();
            }
        }

        #endregion "Public Commands"

        #region "Private Methods"

        private void _authenticationModel_LoginComplete(object sender, LoginOperationEventArgs e)
        {
            if (e.LoginOp.LoginSuccess)
            {
                // login successful, clear the login screen
                CurrentUser = new LoginUser();
            }
            else if (e.HasError)
            {
                LoginScreenErrorMessage = e.LoginOp.Error.Message;
            }
        }

        private void _passwordResetModel_GetUserComplete(object sender, EntityResultsArgs<PasswordResetUser> e)
        {
            if (!e.HasError)
            {
                // found the user, clear the login screen before leaving
                CurrentUser = new LoginUser();
                //populate the password reset screen
                if (e.Results.Count() == 1)
                {
                    var enumerator = e.Results.GetEnumerator();
                    enumerator.MoveNext();
                    CurrentPasswordResetUser = enumerator.Current;

                    // and flip the screen.
                    IsFlipped = true;
                }
            }
            else
            {
                // cannot find the user ID, no need to notify the user either
                // in case someone could use this to find out valid user IDs.
            }
        }

        private void _passwordResetModel_SaveUserComplete(object sender, ResultsArgs e)
        {
            if (!e.HasError)
            {
                // reset password successful, clear the reset password screen before leaving
                CurrentPasswordResetUser = new PasswordResetUser();
                // and flip the screen.
                IsFlipped = false;
            }
            else
            {
                ResetPasswordScreenErrorMessage = e.Error.Message;
            }
        }

        #endregion "Private Methods"
    }
}
